#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>

#define IFFILEERROR(exp,gt) \
		if(!(exp))   \
		{\
			printf("第%d行发生错误:0X%08X\n%s\n",__LINE__, errno, strerror(errno));\
			goto gt;\
		}
#define BUFFERSIZE 16777216 


void progress(int pos)
{
	char str[101];
	str[100] = 0;
	printf("\r[");
	for (int i = 0; i < 100; i++)
	{
		if (i < pos)
		{
			str[i]='>';
		}
		else
		{
			str[i] = ' ';
		}
	}
	printf("%s]%d%%",str, pos);
}



void splic(const char* src, size_t length, const char* desc)
{
	FILE* pf_list =NULL,*pf_src=NULL,*pf_des = NULL;
	char des_name[256];
	size_t src_len,write_len = 0,read_len;
	int fileno = 1;
	char* buf;
	int times_per_des = 1;
	int last_time_size = 0;
	printf("要分割的文件：%s\n要分割的文件快大小:%ld\n输出的分割文件列表为:%s\n",
		src,
		length,
		desc
	);
	if (length > BUFFERSIZE)
	{
		times_per_des = length / BUFFERSIZE;
		last_time_size = length % BUFFERSIZE;
		length = BUFFERSIZE;
	}


	buf = malloc(length);
	
	
	printf("正在分割文件...\n");
	
	pf_src = fopen(src, "rb");
	IFFILEERROR(pf_src!= NULL, finally);
	
	fseek(pf_src, 0, SEEK_END);
	src_len = ftell(pf_src);
	fseek(pf_src, 0, SEEK_SET);
	pf_list = fopen(desc, "w");
	IFFILEERROR(pf_list != NULL, finally);

	while (write_len < src_len)
	{
		sprintf(des_name, "%s.%03d",src ,fileno++);
		pf_des = fopen(des_name, "wb");
		IFFILEERROR(pf_des != NULL, finally);
		fprintf(pf_list, "%s ", des_name);
		
		for (size_t i = 0; i < times_per_des; i++)
		{
			read_len = fread(buf, sizeof(char), length, pf_src);
			IFFILEERROR(fwrite(buf, sizeof(char), read_len, pf_des) == read_len, finally);
			write_len += read_len;
			progress((int)((double)write_len / (double)src_len * 100));
		}
		if (last_time_size)
		{
			read_len = fread(buf, sizeof(char), last_time_size, pf_src);
			IFFILEERROR(fwrite(buf, sizeof(char), read_len, pf_des) == read_len, finally);
			write_len += read_len;
			progress((int)((double)write_len / (double)src_len * 100));
		}
		fclose(pf_des);
	}
	putchar('\n');
	
finally:
	if (pf_src&&feof(pf_src))
	{
		printf("分割成功\n");
	}
	else
	{
		printf("分割失败\n");
	}
	free(buf);
	if (pf_des)
		fclose(pf_des);
	if(pf_list)
		fclose(pf_list);
	if(pf_src)
		fclose(pf_src);
}

void  merge(const char* src,const char* desc)
{
	FILE* pf_list = NULL, * pf_des = NULL, *pf_src = NULL;
	size_t src_size,write_size,read_size;
	char src_name[256];
	char* buf;
	buf = malloc(BUFFERSIZE);
	printf("要合并的文件列表：%s\n合并文件名:%s\n",
		src,
		desc
	);
	
	pf_list = fopen(src,"r");
	IFFILEERROR(pf_list != NULL, finally);

	
	pf_des = fopen(desc, "wb");
	IFFILEERROR(pf_des != NULL, finally);
	
	
	while (fscanf(pf_list, "%s",src_name)!=EOF)
	{
		printf("合并文件%s\n", src_name);
		pf_src = fopen(src_name, "rb");
		IFFILEERROR(pf_src != NULL, finally);
		fseek(pf_src, 0, SEEK_END);
		src_size = ftell(pf_src);
		fseek(pf_src, 0, SEEK_SET);
		write_size = 0;
		while (read_size = fread(buf,sizeof(char), BUFFERSIZE,pf_src))
		{
			IFFILEERROR(fwrite(buf, sizeof(char), read_size, pf_des), finally);
			write_size += read_size;
			progress((int)((double)write_size / src_size * 100.0));
		}
		putchar('\n');
		if (!feof(pf_src))
		{
			fseek(pf_list, 0, SEEK_SET);
			break;
		}
		fclose(pf_src);
		pf_src = NULL;
	}
finally:
	if (pf_list && feof(pf_list))
	{
		printf("合并成功\n");
	}
	else
	{
		printf("合并失败\n");
	}
	if (pf_src)
		fclose(pf_src);
	if(pf_des)
		fclose(pf_des);
	if(pf_list)
		fclose(pf_list);
	free(buf);
	
}

int main(int arcn, char** arcv)
{
	int i;
	char* pch;
	system("pause");
	for (i = 0; i < arcn; i++)
	{
		pch = arcv[i];
		while (i <arcn && *pch == '-')
		{
			if (strcmp(arcv[i],"-t")==0)
			{
				i++;
				if (strcmp(arcv[i],"s")==0)
				{
					if (arcn < i+4)
					{
						printf("参数错误 ： fsplist -t s [要分割的文件] [单个文件大小] [输出列表文件名]\n");
						return -1;
					}
					splic(arcv[i + 1],(size_t)atoll(arcv[i + 2]), arcv[i + 3]);
					i += 4;
				}
				else if (strcmp(arcv[i], "c") == 0)
				{
					if (arcn < i + 3)
					{
						printf("参数错误 ： fsplist -t c [合并文件列表]  [合并输出文件名]\n");
						return -1;
					}
					merge(arcv[i + 1], arcv[i + 2]);
					i += 3;
				}
				else
				{
					printf("参数：\"%s\" 无效\n", arcv[i]);
					return -1;
				}
			}
			else 
			{
				printf("操作:\"%s\"无效\n",arcv[i]);
				return -1;
			}
			
		}
	}


	return 0;
}